package com.liming.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.liming.admin.service.DashboardService;
import com.liming.aftersales.client.AfterSalesClient;
import com.liming.auth.client.UserAuthClient;
import com.liming.common.enums.DateScopeEnum;
import com.liming.common.pojo.vo.dashboard.*;
import com.liming.common.pojo.vo.dashboard.feign.FeignUserConsumeRankVO;
import com.liming.common.pojo.vo.product.openfeign.FeignProductVO;
import com.liming.common.pojo.vo.product.web.ProductVO;
import com.liming.common.pojo.vo.stock.ProductSalesCountVO;
import com.liming.common.util.FeignBeanUtils;
import com.liming.order.client.AdminOrderClient;
import com.liming.product.client.ProductClient;
import com.liming.stock.client.StockClient;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * @author liming
 * @date 2025/3/7
 */
@Service
@AllArgsConstructor
public class DashboardServiceImpl implements DashboardService {

    private final StockClient stockClient;
    private final ProductClient productClient;
    private final AdminOrderClient adminOrderClient;
    private final UserAuthClient userAuthClient;
    private final AfterSalesClient afterSalesClient;

    @Override
    public TopCardVO topCard() {
        TopCardVO vo = new TopCardVO();
        // 销售额
        vo.setTodaySales(getSales(DateScopeEnum.TODAY));
        vo.setMonthlySales(getSales(DateScopeEnum.THIS_MONTH));
        vo.setAnnualSales(getSales(DateScopeEnum.THIS_YEAR));
        // 待处理订单（ 1-已支付, 2-待发货, 4-待自提）
        vo.setUndeliveredOrderCount(adminOrderClient.undeliveredOrderCount());
        // 库存预警数量
        vo.setAlertStockCount(stockClient.alertStockCount());
        // 滞销商品数量（30天未售卖）
        List<FeignProductVO> feignProductVOS = productClient.stagnantProductCount();
        List<ProductVO> stagnantProductList = FeignBeanUtils.toBean(feignProductVOS, ProductVO.class);
        StagnantProductVO stagnantProductVO = new StagnantProductVO();
        stagnantProductVO.setStagnantProductList(stagnantProductList);
        vo.setStagnantProductVO(stagnantProductVO);
        // 热销商品 ***
        HotSalesProductVO hotSalesProductVO = new HotSalesProductVO();
        // 查询库存流水中，库存流水类型为出库的 销量前十的 商品ID
        List<Long> hotSalesProductIds = stockClient.hotSalesProductIds();
        List<FeignProductVO> hotSalesProductList = new ArrayList<>();
        if (CollUtil.isNotEmpty(hotSalesProductIds)) {
            hotSalesProductList = productClient.listByIds(hotSalesProductIds);
        }
        // 查询商品列表
        List<ProductVO> hotProductVO = FeignBeanUtils.toBean(hotSalesProductList, ProductVO.class);
        hotSalesProductVO.setHotSalesProductList(hotProductVO);
        vo.setHotSalesProductCount(hotSalesProductVO);
        // 库存总值
        Map<Long, Integer> productIdAndQuantityMap = stockClient.allProductAvailableQuantityMap();
        Map<Long, Integer> idAndPriceMap = productClient.idAndPriceMap(productIdAndQuantityMap.keySet().stream().toList());
        Integer stockTotal = productIdAndQuantityMap
                .entrySet()
                .stream()
                .map(entry -> entry.getValue() * idAndPriceMap.get(entry.getKey()))
                .reduce(0, Integer::sum);
        vo.setStockTotal(stockTotal);
        return vo;
    }

    /**
     * 根据销售时间范围获取销售总额
     *
     * @param dateScopeEnum 时间范围
     * @return 销售总额
     */
    private Integer getSales(DateScopeEnum dateScopeEnum) {
        List<ProductSalesCountVO> salesCount = stockClient.salesCountByTime(dateScopeEnum);
        if (CollUtil.isEmpty(salesCount)) {
            return 0;
        }
        List<Long> todayProductList = salesCount.stream().map(ProductSalesCountVO::getProductId).toList();
        Map<Long, Integer> idPriceMap = productClient.idAndPriceMap(todayProductList);
        return salesCount.stream().map(today -> today.getSalesCount() * idPriceMap.get(today.getProductId())).reduce(0, Integer::sum);
    }

    @Override
    public List<UserRegister> userRegister(String scope) {
        return userAuthClient.registerDateCount(scope);
    }

    @Override
    public UserTopCardVO userTopCard() {
        UserTopCardVO vo = new UserTopCardVO();
        CompletableFuture<Integer> todayActiveUserFuture = CompletableFuture.supplyAsync(() -> userAuthClient.activityUserCount(DateScopeEnum.TODAY.getScope()));
        CompletableFuture<Integer> yesterdayActiveUserFuture = CompletableFuture.supplyAsync(() -> userAuthClient.activityUserCount(DateScopeEnum.YESTERDAY.getScope()));
        CompletableFuture<Integer> weekActiveUserFuture = CompletableFuture.supplyAsync(() -> userAuthClient.activityUserCount(DateScopeEnum.THIS_WEEK.getScope()));
        CompletableFuture<Integer> lastWeekActiveUserFuture = CompletableFuture.supplyAsync(() -> userAuthClient.activityUserCount(DateScopeEnum.LAST_WEEK.getScope()));
        CompletableFuture.allOf(todayActiveUserFuture, yesterdayActiveUserFuture, weekActiveUserFuture, lastWeekActiveUserFuture).join();
        CompletableFuture<Integer> monthActiveUserFuture = CompletableFuture.supplyAsync(() -> userAuthClient.activityUserCount(DateScopeEnum.THIS_MONTH.getScope()));
        CompletableFuture<Integer> lastMonthActiveUserFuture = CompletableFuture.supplyAsync(() -> userAuthClient.activityUserCount(DateScopeEnum.LAST_MONTH.getScope()));
        CompletableFuture<Long> userCountFuture = CompletableFuture.supplyAsync(userAuthClient::userCount);
        CompletableFuture<Map<Long, Double>> userActivityScoreFuture = CompletableFuture.supplyAsync(userAuthClient::allUserActivityScore);
        CompletableFuture.allOf(monthActiveUserFuture, lastMonthActiveUserFuture, userCountFuture, userActivityScoreFuture).join();

        // 今日
        Integer todayActiveUser = todayActiveUserFuture.join();
        vo.setTodayActiveUser(todayActiveUser);
        // 相较于昨日
        Integer yesterdayActiveUser = yesterdayActiveUserFuture.join();
        vo.setTodayActiveUserRatio(0.0);
        if (ObjectUtil.notEqual(yesterdayActiveUser, 0) && ObjectUtil.isNotNull(yesterdayActiveUser)) {
            vo.setTodayActiveUserRatio((todayActiveUser - yesterdayActiveUser) / (double) yesterdayActiveUser);
        }
        // 本周
        Integer weekActiveUser = weekActiveUserFuture.join();
        vo.setWeekActiveUser(weekActiveUser);
        // 相较于上周
        Integer lastWeekActiveUser = lastWeekActiveUserFuture.join();
        vo.setWeekActiveUserRatio(0.0);
        if (ObjectUtil.notEqual(lastWeekActiveUser, 0) && ObjectUtil.isNotNull(lastWeekActiveUser)) {
            vo.setWeekActiveUserRatio((weekActiveUser - lastWeekActiveUser) / (double) lastWeekActiveUser);
        }
        // 本月
        Integer monthActiveUser = monthActiveUserFuture.join();
        vo.setMonthActiveUser(monthActiveUser);
        // 相较于上月
        Integer lastMonthActiveUser = lastMonthActiveUserFuture.join();
        vo.setMonthActiveUserRatio(0.0);
        if (ObjectUtil.notEqual(lastMonthActiveUser, 0) && ObjectUtil.isNotNull(lastMonthActiveUser)) {
            vo.setMonthActiveUserRatio((monthActiveUser - lastMonthActiveUser) / (double) lastMonthActiveUser);
        }
        // 总用户数
        vo.setTotalUser(userCountFuture.join());
        // 用户活跃率
        Map<Long, Double> userIdAndScore = userActivityScoreFuture.join();
        double totalUserActivityRatio = userIdAndScore.values().stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
        vo.setTotalUserActivityRatio(totalUserActivityRatio);
        return vo;
    }

    @Override
    public Map<Integer, Long> userGender() {
        return userAuthClient.genderQuantityMap();
    }

    @Override
    public List<UserConsumeRankVO> userConsumeRank() {
        Map<Long, String> userIdsAndNicknameMap = userAuthClient.userIdsAndNickname();
        // 获取各个用户的订单数量，所有订单的合计金额，最近下单时间
        List<FeignUserConsumeRankVO> feignResult = adminOrderClient.userConsumeRank(userIdsAndNicknameMap);
        return FeignBeanUtils.toBean(feignResult, UserConsumeRankVO.class);
    }

    @Override
    public CustomerReviewTopCardVO customerReviewTopCard() {
        return afterSalesClient.topCard();
    }
}
